package com.dizner.androidcarclient;

import android.os.Handler;
import android.os.Message;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;

import com.google.gson.Gson;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;

public class SocketClient {


    private static final SocketClient ourInstance = new SocketClient();

    private static final String TAG = "SocketClient";

    private Socket socket;

    private String targetIp; //目标地址
    private int targetPort; //目标端口

    private TreeMap<Integer, OnMessageListener> listeners;

    static SocketClient getInstance() {
        return ourInstance;
    }


    private SocketClient() {

    }

    public void startClient(String targetIp, int targetPort) {
        initClient(targetIp, targetPort);
    }


    public <T> void register(@NonNull OnMessageListener listener) {
        if (listeners == null) {
            listeners = new TreeMap<>();
        }
        listeners.put(listener.hashCode(), listener);
    }

    public void unRegister(@NonNull OnMessageListener listener) {
        if (listeners != null) {
            listeners.remove(listener.hashCode());
        }
    }

    private int connectedCount = 0;

    /**
     * 初始化SocketClient
     *
     * @throws IOException
     */
    private void initClient(final String targetIp, final int targetPort) {
        this.targetIp = targetIp;
        this.targetPort = targetPort;
        connectedCount = 0;
        new Thread() {
            @Override
            public void run() {
                while (true) {
                    if (connectedCount >= 1) {
                        break;
                    }
                    try {
                        if (socket != null) {
                            socket.close();
                            socket = null;
                        }
                        Log.i(TAG, "正在连接");
                        socket = new Socket(targetIp, targetPort);
                        Log.i(TAG, "连接成功");
                        mHandler.sendEmptyMessage(Msg_Type.STATUS_CONNECT);
                        char[] buffer = new char[1024];
                        int len = -1;
                        InputStreamReader inputStreamReader = new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8);
                        BufferedReader reader = new BufferedReader(inputStreamReader);
                        String data = null;
                        while ((data = reader.readLine()) != null) {
                            Log.i(TAG, "收到服务端的数据-----------------------------:" + data);
                            if (!TextUtils.isEmpty(data)) {
                                try {
                                    JSONObject jsonObject = new JSONObject(data);
                                    int msgType = jsonObject.optInt("type");
                                    Message message = mHandler.obtainMessage();
                                    message.what = msgType;
                                    message.obj = data;
                                    mHandler.sendMessage(message);
                                } catch (JSONException e) {
                                    e.printStackTrace();
                                }
                            }
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    } finally {
                        try {
                            Log.i(TAG, "连接断开，重新连接");
                            if (socket != null) {
                                socket.close();
                            }
                        } catch (IOException e) {
                            e.printStackTrace();
                        } finally {
                            connectedCount++;
                            mHandler.sendEmptyMessage(Msg_Type.STATUS_DIS_CONNECT);
                        }
                    }
                }

            }
        }.start();
    }

    public void sendMsg(final String msg) {

        if (socket == null || !socket.isConnected()) {
            new Thread() {
                @Override
                public void run() {
                    try {
                        socket = new Socket(targetIp, targetPort);
                        PrintWriter output = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8), true);
                        output.write(msg);
                        output.write("\n");
                        socket.getOutputStream().flush();
                        output.flush();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }.start();
        } else {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        PrintWriter output = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8), true);
                        Log.i(TAG, msg);
                        output.write(msg);
                        output.write("\n");
                        socket.getOutputStream().flush();
                        output.flush();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }


    }

    private Handler mHandler = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            switch (msg.what) {
                case Msg_Type.MSG_CHARACTER:
                    Log.i(TAG, "收到字符消息----:" + msg.obj.toString());
                    requestCallbackByMsg(msg.obj.toString());
                    break;
                case Msg_Type.MSG_CONTROL:
                    Log.i(TAG, "收到控制消息----:" + msg.obj.toString());
                    requestCallbackByMsg(msg.obj.toString());
                    break;
                case Msg_Type.MSG_SYSTEM:
                    requestCallbackByMsg(msg.obj.toString());
                    Log.i(TAG, "收到系统消息----:" + msg.obj.toString());
                    break;
                case Msg_Type.STATUS_CONNECT:
                    requestCallbackByConnect();
                    break;
                case Msg_Type.STATUS_DIS_CONNECT:
                    requestCallbackByDisConnect();
                    break;
            }
            return false;
        }
    });

    private void requestCallbackByMsg(String msg) {
        if (listeners != null) {
            Iterator<Map.Entry<Integer, OnMessageListener>> iterator = listeners.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry<Integer, OnMessageListener> next = iterator.next();
                if (next.getValue() != null) {
                    convertObj(msg, next.getValue());
                }
            }
        }
    }

    private void requestCallbackByConnect() {
        if (listeners != null) {
            Iterator<Map.Entry<Integer, OnMessageListener>> iterator = listeners.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry<Integer, OnMessageListener> next = iterator.next();
                if (next.getValue() != null) {
                    next.getValue().onConnect();
                }
            }
        }
    }

    private void requestCallbackByScanResult() {
        if (listeners != null) {
            Iterator<Map.Entry<Integer, OnMessageListener>> iterator = listeners.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry<Integer, OnMessageListener> next = iterator.next();
                if (next.getValue() != null) {
                    next.getValue().onScanResult(targetIp);
                }
            }
        }
    }

    private void requestCallbackByDisConnect() {
        if (listeners != null) {
            Iterator<Map.Entry<Integer, OnMessageListener>> iterator = listeners.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry<Integer, OnMessageListener> next = iterator.next();
                if (next.getValue() != null) {
                    next.getValue().onDisconnect();
                }
            }
        }
    }

    private void convertObj(String str, OnMessageListener value) {
        if (TextUtils.isEmpty(str)) {
            return;
        }
        if (value == null) {
            return;
        }

        Log.i(TAG, str);


        Gson gson = new Gson();

        value.onMessage(gson.fromJson(str, BaseMessage.class));


    }


    private void initBroacastRecover() {
        try {
            recoverDatagramSocket = new DatagramSocket(1099);
        } catch (Exception e) {
            e.printStackTrace();
        }
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        byte buf[] = new byte[1024];
                        DatagramPacket data = new DatagramPacket(buf, buf.length);
                        recoverDatagramSocket.receive(data);
                        String content = new String(data.getData()).trim();
                        if (!TextUtils.isEmpty(content) && content.startsWith("CAR_CONTROL_ACCESS")) {
                            targetIp = data.getAddress().getHostAddress();
                            mHandler.post(new Runnable() {
                                @Override
                                public void run() {
                                    requestCallbackByScanResult();
//                                    Log.i(TAG, "目标地址是：" + targetIp);
                                }
                            });
                            return;
                        }
//                        Log.i(TAG, "-----" + content);
//                        Thread.sleep(1000);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }

    DatagramSocket sendDatagramSocket = null;
    DatagramSocket recoverDatagramSocket = null;

    public void scanCarServer() {
        final String msg = "START_IP_BROD_CAST";

        try {
            sendDatagramSocket = new DatagramSocket();
            sendDatagramSocket.setBroadcast(true);
        } catch (SocketException e) {
            e.printStackTrace();
        }
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        DatagramPacket data = new DatagramPacket(msg.getBytes(), msg.length(), InetAddress.getByName("255.255.255.255"), 1099);
                        sendDatagramSocket.send(data);
                        Thread.sleep(1000);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();

        initBroacastRecover();

    }


    public boolean isConnected() {
        if (socket != null) {
            return socket.isConnected();
        }
        return false;
    }

    public void close() {
        if (socket != null) {
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    static interface OnMessageListener {
        void onMessage(BaseMessage t);

        void onScanResult(String targetIp);

        void onConnect();

        void onDisconnect();
    }

    static class Msg_Type {
        final static int MSG_CONTROL = 0x1;//控制消息
        final static int MSG_SYSTEM = 0x2;//系统消息
        final static int MSG_CHARACTER = 0x3;//字符串消息
        final static int STATUS_CONNECT = 0x4;//连接成功
        final static int STATUS_DIS_CONNECT = 0x5;//断开连接
    }
}
